package com.abel.bigwater.data.jnrq

import com.abel.bigwater.data.InvalidPacketException
import com.abel.bigwater.data.UnknownPacketException
import io.netty.buffer.ByteBuf
import kotlin.collections.ArrayList
import kotlin.experimental.and

/** 包长： 25+24*N（N 为表个数）。*/
class UploadHistoryData : JnrqData {

    constructor(_packet: JnrqPacket) {
        packet = _packet

        computeDataLen()
    }

    /**
     * 计算数据长度，针对解析和打包
     */
    override fun computeDataLen(): Int {
        if (packet?.len != null) {
            // 解析
            dataLen = packet.len!! - 13
            numberMeter = (packet.len!! - 25) / 24
        } else {
            // 打包
            numberMeter = waterList?.size
            dataLen = 12 + 24 * (numberMeter ?: 0)
        }

        return dataLen!!
    }

    val packet: JnrqPacket?

    var dataType: JnrqDataType? = null

    var volt: Short? = null

    /** 流水号*/
    var aiNo: Short? = null

    /** 包长： 25+24*N（N 为表个数）。*/
    var numberMeter: Int? = null

    /**
     * 记录内容字段 N*M*XXH，其中 N 为表具的个数， M 为单个表具的数据长度，水表为 24
    个字节 ，混合/热量表，流量计为 60 个字节；
    单个表具数据结构如下表所示
     */
    var waterList: Array<JnrqReadData>? = null

    /**
     * 从当前位置写入打包字节流
     */
    override fun fillBuffer(buf: ByteBuf) {
        val tmp = buf.alloc().buffer()

        tmp.writeByte(dataType!!.code.toInt())

        tmp.writeByte(0).writeByte(0)

        tmp.writeByte(rssi!!.toInt())

        tmp.writeByte(0).writeByte(0)

        tmp.writeByte(sendPacketCount!!.toInt()).writeByte(recvPacketCount!!.toInt())

        tmp.writeByte(volt!!.toInt())

        tmp.writeByte(aiNo!!.toInt())

        tmp.writeByte(swVersion!!.toInt())

        tmp.writeByte(0)

        for (data in waterList.orEmpty()) {
            data.fillBuffer(tmp)
        }

        // write valid bytes.
        buf.writeBytes(tmp)
    }

    /**
     * 解析字节流，从buf当前位置开始，并且消费其中的字节。
     */
    @Throws(NullPointerException::class, UnknownPacketException::class, InvalidPacketException::class)
    override fun parseBuffer(buf: ByteBuf) {
        // dataLen is set already.
        val tmp = buf.duplicate()
        fun readByteAsShort() = tmp.readByte().toShort() and 0xFF

        val _code = readByteAsShort()
        dataType = JnrqDataType.findByCode(_code)
        if (dataType == null) throw UnknownPacketException("不识别的数据类型: ${_code.toString(16)}")

        //包长： 25+24*N（N 为表个数）
        numberMeter = (dataLen!! - 25 + 13) / dataType!!.fixedLen

        // 报文中登陆时长/时刻、 GPRS 打开/成功次数、回复序号默认为 00H，不启用。
        tmp.skipBytes(2)

        rssi = readByteAsShort()

        tmp.skipBytes(2)

        sendPacketCount = readByteAsShort()
        recvPacketCount = readByteAsShort()

        volt = readByteAsShort()
        aiNo = readByteAsShort()
        swVersion = readByteAsShort()

        // 回复序号
        tmp.skipBytes(1)

        val list = ArrayList<JnrqReadData>()
        for (idx in 0..(numberMeter!! - 1)) {
            list.add(
                    when (dataType) {
                        JnrqDataType.WaterMeter -> WaterMeterData().apply { parseBuffer(tmp) }
                        JnrqDataType.FlowGauge -> FLowGaugeData().apply { parseBuffer(tmp) }
                        else -> throw UnknownPacketException("unknown packet type: ${dataType}")
                    })
        }

        waterList = list.toTypedArray()

        // skip valid bytes
        buf.skipBytes(dataLen!!)
    }
}

enum class JnrqDataType {
    WaterMeter(1, 24),
    HotMeter(0, 80),
    FlowGauge(3, 60);

    val code: Short

    val fixedLen: Short

    constructor(_code: Short, _len: Short) {
        code = _code
        fixedLen = _len
    }

    companion object {
        /**
         * 按code查找枚举值
         */
        fun findByCode(_code: Short): JnrqDataType? {
            return JnrqDataType.values().find { it.code == _code }
        }
    }
}

